package com.hardy.demo.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.*;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * Author: Hardy
 * Date:   2020/12/29
 * Description:
 **/
public class SpringBean {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(SpringBean.class);
        context.refresh();

        User bean = context.getBean(User.class);
        context.close();
    }

    @Bean
    private User user() {
        User user = new User();
        user.setName("hahahaha");
        return user;
    }

    //@Bean
    private A a() {
        return new A();
    }

    @Bean
    private BeanPostProcessor postProcessor() {
        return new MyBeanPostProcessor();
    }

    @Bean
    private InstantiationAwareBeanPostProcessor instantiationAwareBeanPostProcessor() {
        return new MyInstantiationAwareBeanPostProcessor();
    }

    @Bean
    private BeanFactoryPostProcessor BeanFactoryPostProcessor() {
        return new MyBeanFactoryPostProcessor();
    }

    class User implements BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean {
        private String name;

        public User() {
            System.out.println("User: 构造方法");
        }

        public String getName() {
            System.out.println("User: GET方法");
            return name;
        }

        public void setName(String name) {
            System.out.println("User: SET方法");
            this.name = name;
        }

        @Override
        public void setBeanName(String name) {
            System.out.println("BeanNameAware.setBeanName -> " + this + ", BeanName : " + name);
        }

        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("BeanFactoryAware.setBeanFactory -> " + beanFactory.getBean(User.class));
        }

        @Override
        public void afterPropertiesSet() {
            System.out.println("InitializingBean.afterPropertiesSet -> " + this);
        }

        @Override
        public void destroy() {
            System.out.println("DisposableBean.destroy -> " + this);
        }

        @PostConstruct
        public void init() {
            System.out.println("@PostConstruct -> " + this);
        }

        @PreDestroy
        public void preDestroy() {
            System.out.println("@PreDestroy -> " + this);
        }

        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

    class MyBeanPostProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("BeanPostProcessor.postProcessBeforeInitialization -> bean: " + bean + ", beanName: " + beanName);
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("BeanPostProcessor.postProcessAfterInitialization -> bean: " + bean + ", beanName: " + beanName);
            return bean;
        }
    }

    class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("InstantiationAwareBeanPostProcessor.postProcessBeforeInitialization -> bean: " + bean + ", beanName: " + beanName);
            return bean;
        }

        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("InstantiationAwareBeanPostProcessor.postProcessAfterInitialization -> bean: " + bean + ", beanName: " + beanName);
            return bean;
        }

        @Override
        public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
            System.out.println("InstantiationAwareBeanPostProcessor.postProcessProperties -> bean: " + bean + ", beanName: " + beanName);
            return pvs;
        }
    }

    class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            System.out.println("BeanFactoryPostProcessor.postProcessBeanFactory -> " + beanFactory.getClass());
        }
    }

    class A {
        private int age;

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }
    }
}
